From 9e1f58146508dfc462ca68246582d1136ee8191d Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Mon, 14 Nov 2016 00:45:15 +0100 Subject: [PATCH] babl: cache state between babl runs Store the contents of discovered babl_paths between runs, for now in /tmp/babl.db , should move to a per-user dir to make it survive reboots. The code should also check a versioning string at the start and bail if there is any mismatch... since the data should be reconstructable; and more reliable when reconstructed than a possibly old version. --- babl/babl-fish-path.c | 31 +++--- babl/babl.c | 245 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 14 deletions(-) diff --git a/babl/babl-fish-path.c b/babl/babl-fish-path.c index bf9c520..f15d0e2 100644 --- a/babl/babl-fish-path.c +++ b/babl/babl-fish-path.c @@ -88,11 +88,11 @@ get_conversion_path (PathContext *pc, int current_length, int max_length); -static char * -create_name (char *buf, - const Babl *source, - const Babl *destination, - int is_reference); +char * +_babl_fish_create_name (char *buf, + const Babl *source, + const Babl *destination, + int is_reference); static double legal_error (void); @@ -238,11 +238,11 @@ get_conversion_path (PathContext *pc, } } -static char * -create_name (char *buf, - const Babl *source, - const Babl *destination, - int is_reference) +char * +_babl_fish_create_name (char *buf, + const Babl *source, + const Babl *destination, + int is_reference) { /* fish names are intentionally kept short */ snprintf (buf, BABL_MAX_NAME_LEN, "%s %p %p", "", @@ -250,8 +250,11 @@ create_name (char *buf, return buf; } -static int -babl_fish_path_destroy (void *data) +int +_babl_fish_path_destroy (void *data); + +int +_babl_fish_path_destroy (void *data) { Babl *babl=data; if (babl->fish_path.conversion_list) @@ -267,7 +270,7 @@ babl_fish_path (const Babl *source, Babl *babl = NULL; char name[BABL_MAX_NAME_LEN]; - create_name (name, source, destination, 1); + _babl_fish_create_name (name, source, destination, 1); babl = babl_db_exist_by_name (babl_fish_db (), name); if (babl) { @@ -279,7 +282,7 @@ babl_fish_path (const Babl *source, babl = babl_calloc (1, sizeof (BablFishPath) + strlen (name) + 1); - babl_set_destructor (babl, babl_fish_path_destroy); + babl_set_destructor (babl, _babl_fish_path_destroy); babl->class_type = BABL_FISH_PATH; babl->instance.id = babl_fish_get_id (source, destination); diff --git a/babl/babl.c b/babl/babl.c index 0484d30..1287383 100644 --- a/babl/babl.c +++ b/babl/babl.c @@ -124,6 +124,244 @@ babl_dir_list (void) return ret; } +static char * +babl_fish_serialize (Babl *fish, char *dest, int n) +{ + switch (fish->class_type) + { + case BABL_FISH_PATH: + { + char *d = dest; + + snprintf (d, n, "%s\n%s\n", + babl_get_name (fish->fish.source), + babl_get_name (fish->fish.destination)); + n -= strlen (d);d += strlen (d); + + snprintf (d, n, "\terror=%f", fish->fish.error); + n -= strlen (d);d += strlen (d); + + snprintf (d, n, " processings=%i", fish->fish.processings); + n -= strlen (d);d += strlen (d); + + snprintf (d, n, " pixels=%li", fish->fish.pixels); + n -= strlen (d);d += strlen (d); + + snprintf (d, n, " cost=%f", fish->fish_path.cost); + n -= strlen (d);d += strlen (d); + + snprintf (d, n, " loss=%f", fish->fish_path.loss); + n -= strlen (d);d += strlen (d); + + snprintf (d, n, "\n"); + n -= strlen (d);d += strlen (d); + + for (int i = 0; i < fish->fish_path.conversion_list->count; i++) + { + snprintf (d, n, "\t%s\n", + babl_get_name(fish->fish_path.conversion_list->items[i] )); + n -= strlen (d); + d += strlen (d); + } + } + break; + case BABL_FISH_SIMPLE: + return NULL; + break; + case BABL_FISH_REFERENCE: + return NULL; break; + default: + break; + } + + return dest; +} + +static const char *fish_cache_path (void) +{ + return "/tmp/babl.db"; // XXX: a $HOME/.cache/babl/fishes path might be better +} + +static void babl_store_db (void) +{ + BablDb *db = babl_fish_db (); + int i; + FILE *dbfile = fopen (fish_cache_path (), "w"); + if (!dbfile) + return; + fprintf (dbfile, "#babl 0 %i fishes\n", db->babl_list->count); + for (i = 0; i< db->babl_list->count; i++) + { + Babl *fish = db->babl_list->items[i]; + char tmp[8192]; + if (babl_fish_serialize (fish, tmp, 4096)) + fprintf (dbfile, "%s----\n", tmp); + } + fclose (dbfile); +} + +static int +babl_file_get_contents (const char *path, + char **contents, + long *length, + void *error) +{ + FILE *file; + long size; + char *buffer; + + file = fopen (path,"rb"); + + if (!file) + return -1; + + fseek (file, 0, SEEK_END); + size = ftell (file); + if (length) *length = size; + rewind (file); + buffer = malloc(size + 8); + + if (!buffer) + { + fclose(file); + return -1; + } + + size -= fread (buffer, 1, size, file); + if (size) + { + fclose (file); + free (buffer); + return -1; + } + fclose (file); + *contents = buffer; + return 0; +} + +int +_babl_fish_path_destroy (void *data); + +char * +_babl_fish_create_name (char *buf, + const Babl *source, + const Babl *destination, + int is_reference); + +static void babl_init_db (const char *path) +{ + long length = -1; + char seps[] = "\n"; + Babl *babl = NULL; + char *contents = NULL; + char *token; + char *tokp; + const Babl *from_format = NULL; + const Babl *to_format = NULL; +#ifdef _WIN32 // XXX: fixme - make this work on windows + return; +#endif + + babl_file_get_contents (path, &contents, &length, NULL); + if (!contents) + return; + + token = strtok_r (contents, seps, &tokp); + while( token != NULL ) + { + switch (token[0]) + { + case '-': /* finalize */ + //fprintf (stderr, "%p %p\n", from_format, to_format); + if (babl) + babl_db_insert (babl_fish_db(), babl); + from_format = NULL; + to_format = NULL; + babl=NULL; + break; + case '#': + break; + case '\t': + if (strchr (token, '=')) + { + char seps2[] = " "; + char *tokp2; + char *token2; + char name[4096]; + + _babl_fish_create_name (name, from_format, to_format, 1); + babl = babl_db_exist_by_name (babl_fish_db (), name); + if (babl) + { + fprintf (stderr, "%s:%i: loading of cache failed\n", + __FUNCTION__, __LINE__); + return; + } + + babl = babl_calloc (1, sizeof (BablFishPath) + + strlen (name) + 1); + babl_set_destructor (babl, _babl_fish_path_destroy); + + babl->class_type = BABL_FISH_PATH; + babl->instance.id = babl_fish_get_id (from_format, to_format); + babl->instance.name = ((char *) babl) + sizeof (BablFishPath); + strcpy (babl->instance.name, name); + babl->fish.source = from_format; + babl->fish.destination = to_format; + babl->fish_path.conversion_list = babl_list_init_with_size (10); + + token2 = strtok_r (&token[1], seps2, &tokp2); + while( token2 != NULL ) + { + if (!strncmp (token2, "error=", 6)) + { + babl->fish.error = strtod (token2 + 6, NULL); + } + else if (!strncmp (token2, "cost=", 5)) + { + babl->fish_path.cost = strtod (token2 + 5, NULL); + } + else if (!strncmp (token2, "loss=", 5)) + { + babl->fish_path.loss = strtod (token2 + 5, NULL); + } + else if (!strncmp (token2, "pixels=", 7)) + { + babl->fish.pixels = strtol (token2 + 7, NULL, 10); + } + else if (!strncmp (token2, "processings=", 12)) + { + babl->fish.processings = strtol (token2 + 12, NULL, 10); + } + token2 = strtok_r (NULL, seps2, &tokp2); + } + } + else + { + Babl *conv = + (void*)babl_db_find(babl_conversion_db(), &token[1]); + if (!conv) + { + return; + } + else + babl_list_insert_last (babl->fish_path.conversion_list, conv); + } + break; + default: + if (!from_format) + from_format = babl_format (token); + else + to_format = babl_format (token); + + break; + } + token = strtok_r (NULL, seps, &tokp); + } + if (contents) + free (contents); +} + void babl_init (void) { @@ -150,6 +388,8 @@ babl_init (void) dir_list = babl_dir_list (); babl_extension_load_dir_list (dir_list); babl_free (dir_list); + + babl_init_db (fish_cache_path()); } } @@ -158,6 +398,11 @@ babl_exit (void) { if (!-- ref_count) { +#ifdef _WIN32 // XXX: fixme - make this work on windows +#else + babl_store_db (); +#endif + if (getenv ("BABL_STATS")) { char logfile_name[] = "/tmp/babl-stats.html"; -- 2.30.2